<template>
  <div
    class="czr-table"
    :class="{
      'czr-table-normal': !otherStyle,
      'czr-table-full': full !== false,
    }"
    ref="ref_czrTable"
  >
    <div
      class="czr-table-main"
      ref="ref_tableMain"
      :class="{ 'czr-table-main-no-foot': noFoot !== false }"
    >
      <el-table
        v-if="state.dragRefresh"
        v-bind="$attrs"
        class="ct-table"
        ref="ref_table"
        :data="data"
        :border="true"
        @sort-change="handleSort"
        @filter-change="handleFilter"
        @selection-change="
          (v) => !state.waitSelected && $emit('update:selected', v)
        "
      >
        <el-table-column
          v-if="dragable !== false"
          :width="50"
          align="center"
          fixed="left"
          prop="drag"
        >
          <template #default="scope">
            <SvgIcon
              class="__hover drag-icon"
              name="czr_move"
              color="#000000"
            />
          </template>
        </el-table-column>
        <el-table-column
          v-if="selected"
          type="selection"
          :width="selectWidth"
          align="center"
          :selectable="selectable"
        />
        <el-table-column
          v-if="singled"
          :width="singledWidth"
          align="center"
          class-name="single-column"
          fixed="left"
        >
          <template #default="scope">
            <template v-if="!singleable || singleable(scope)">
              <div
                class="single-circle"
                :class="{ active: scope.row[idKey] === singled[idKey] }"
                @click.stop="$emit('update:singled', scope.row)"
              >
                <div class="single-circle-in"></div>
              </div>
            </template>
          </template>
        </el-table-column>
        <el-table-column
          v-if="showIndex"
          type="index"
          label="序号"
          align="center"
          fixed="left"
          width="60"
        />
        <!--        一级-->
        <template v-for="(one, oneI) in state.tempTableHead" :key="oneI">
          <template v-if="one.children?.length > 0">
            <el-table-column :label="one.label" v-if="one.show" align="center">
              <!--              二级-->
              <template v-for="(two, twoI) in one.children" :key="twoI">
                <template v-if="two.children?.length > 0">
                  <el-table-column
                    :label="two.label"
                    v-if="two.show"
                    align="center"
                  >
                    <!--                    三级-->
                    <template
                      v-for="(three, threeI) in two.children"
                      :key="threeI"
                    >
                      <template v-if="three.children?.length > 0">
                        <el-table-column
                          :label="three.label"
                          v-if="three.show"
                          align="center"
                        >
                          <!--                          四级-->
                          <template
                            v-for="(four, fourI) in three.children"
                            :key="fourI"
                          >
                            <template v-if="four.children?.length > 0">
                              <el-table-column
                                :label="four.label"
                                v-if="four.show"
                                align="center"
                              >
                                <!--                                五级-->
                                <template
                                  v-for="(five, fiveI) in four.children"
                                  :key="fiveI"
                                >
                                  <CzrTableColumn :item="five" v-if="five.show">
                                    <template
                                      #[`${five.value}-column`]="{ column }"
                                    >
                                      <slot
                                        :name="`${five.value}-column`"
                                        :column="column"
                                      >
                                      </slot>
                                    </template>
                                    <template
                                      #[`${five.value}-column-value`]="{
                                        scope,
                                      }"
                                    >
                                      <slot
                                        :name="`${five.value}-column-value`"
                                        :scope="scope"
                                      >
                                      </slot>
                                    </template>
                                    <template
                                      #[`${five.value}-header-value`]="{
                                        scope,
                                      }"
                                    >
                                      <slot
                                        :name="`${five.value}-header-value`"
                                        :scope="scope"
                                      >
                                      </slot>
                                    </template>
                                  </CzrTableColumn>
                                </template>
                              </el-table-column>
                            </template>
                            <template v-else>
                              <CzrTableColumn :item="four" v-if="four.show">
                                <template
                                  #[`${four.value}-column`]="{ column }"
                                >
                                  <slot
                                    :name="`${four.value}-column`"
                                    :column="column"
                                  >
                                  </slot>
                                </template>
                                <template
                                  #[`${four.value}-column-value`]="{ scope }"
                                >
                                  <slot
                                    :name="`${four.value}-column-value`"
                                    :scope="scope"
                                  >
                                  </slot>
                                </template>
                                <template
                                  #[`${four.value}-header-value`]="{ scope }"
                                >
                                  <slot
                                    :name="`${four.value}-header-value`"
                                    :scope="scope"
                                  >
                                  </slot>
                                </template>
                              </CzrTableColumn>
                            </template>
                          </template>
                        </el-table-column>
                      </template>
                      <template v-else>
                        <CzrTableColumn :item="three" v-if="three.show">
                          <template #[`${three.value}-column`]="{ column }">
                            <slot
                              :name="`${three.value}-column`"
                              :column="column"
                            >
                            </slot>
                          </template>
                          <template
                            #[`${three.value}-column-value`]="{ scope }"
                          >
                            <slot
                              :name="`${three.value}-column-value`"
                              :scope="scope"
                            >
                            </slot>
                          </template>
                          <template
                            #[`${three.value}-header-value`]="{ scope }"
                          >
                            <slot
                              :name="`${three.value}-header-value`"
                              :scope="scope"
                            >
                            </slot>
                          </template>
                        </CzrTableColumn>
                      </template>
                    </template>
                  </el-table-column>
                </template>
                <template v-else>
                  <CzrTableColumn :item="two" v-if="two.show">
                    <template #[`${two.value}-column`]="{ column }">
                      <slot :name="`${two.value}-column`" :column="column">
                      </slot>
                    </template>
                    <template #[`${two.value}-column-value`]="{ scope }">
                      <slot :name="`${two.value}-column-value`" :scope="scope">
                      </slot>
                    </template>
                    <template #[`${two.value}-header-value`]="{ scope }">
                      <slot :name="`${two.value}-header-value`" :scope="scope">
                      </slot>
                    </template>
                  </CzrTableColumn>
                </template>
              </template>
            </el-table-column>
          </template>
          <template v-else>
            <CzrTableColumn :item="one" v-if="one.show">
              <template #[`${one.value}-column`]="{ column }">
                <slot :name="`${one.value}-column`" :column="column"> </slot>
              </template>
              <template #[`${one.value}-column-value`]="{ scope }">
                <slot :name="`${one.value}-column-value`" :scope="scope">
                </slot>
              </template>
              <template #[`${one.value}-header-value`]="{ scope }">
                <slot :name="`${one.value}-header-value`" :scope="scope">
                </slot>
              </template>
            </CzrTableColumn>
          </template>
        </template>
      </el-table>
    </div>
    <div
      class="ct-block"
      :style="`height: ${state.tableContentHeight}px;`"
      v-if="full === false && state.showBlock && noFoot === false"
    />
    <div class="ct-foot" v-if="noFoot === false">
      <div class="total">
        <template v-if="isValue(selectedNum)">
          已选中 {{ selectedNum }} 条 /
        </template>
        <template v-else-if="isValue(selected?.length)">
          已选中 {{ selected.length }} 条 /
        </template>
        共 {{ isValue(total) ? total : data.length }} 条
      </div>
      <el-pagination
        v-if="noPage === false"
        ref="ref_tablePage"
        class="__czr-pagination"
        :current-page="page"
        :page-size="pageSize"
        background
        :page-sizes="pageSizes"
        :layout="pageLayoutCpt"
        :total="Number(total)"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: 'CzrTable',
})
import { isValue } from '@/utils/czr-util'
import {
  computed,
  onMounted,
  ref,
  reactive,
  watch,
  nextTick,
  onBeforeUnmount,
} from 'vue'
import Sortable from 'sortablejs'
const emit = defineEmits([
  'handlePage',
  'handleSort',
  'update:data',
  'handleFilter',
  'update:selected',
])
const props = defineProps({
  data: {
    required: true,
  },
  head: {
    default: () => [],
    required: true,
  },
  total: {},
  page: {},
  pageSize: {},
  pageSizes: {
    default: () => [10, 20, 30, 50, 100],
  },
  selected: {
    default: null,
  },
  selectedNum: {
    default: null,
  },
  selectWidth: {
    default: 50,
  },
  singledWidth: {
    default: 50,
  },
  singled: {
    default: null,
  },
  singleable: {},
  noPage: {
    default: false,
  },
  showIndex: {
    default: true,
  },
  otherStyle: {
    default: false,
  },
  noLayout: {
    default: () => [],
  },
  full: {
    default: false,
  },
  selectable: {},
  noFoot: {
    default: false,
  },
  dragable: {
    default: false,
  },
  idKey: {
    default: 'id',
  },
  showLast: {
    default: true,
  },
})
const ref_czrTable = ref()
const ref_table = ref()
const ref_tableMain = ref()
const ref_tablePage = ref()
const state = reactive({
  tempTableHead: <any>[],
  pageLayout: ['sizes', 'prev', 'pager', 'next', 'jumper'],
  tableContentHeight: 0,
  showBlock: false,
  tableResizeFlag: false,
  dragRefresh: true,
  waitSelected: false,
})
watch(
  () => props.head,
  (nVal: any) => {
    formatTableHead(nVal)
  },
  { deep: true },
)
const pageLayoutCpt = computed(() => {
  return state.pageLayout
    .filter((v: string) => props.noLayout.every((s: string) => v !== s))
    .join(',')
})

const formatTableHead = (head: Array<any>) => {
  const result = JSON.parse(
    JSON.stringify(props.showLast ? head : head.slice(0, head.length - 1)),
  )
  const deep = (arr: any[]) => {
    let flag = 0
    arr.forEach((v) => {
      if (v.children && v.children.length > 0) {
        v.show = deep(v.children)
      }
      if (v.show) {
        flag++
      }
    })
    return flag > 0
  }
  deep(result)
  state.tempTableHead = result
}
const handleSizeChange = (val: Number) => {
  emit('handlePage', 1, val)
}
const handleCurrentChange = (val: Number) => {
  emit('handlePage', val, props.pageSize)
}
const handleSort = ({ column, prop, order }: any) => {
  emit('handleSort', {
    key: prop,
    value: order,
  })
}
const handleFilter = (val: any) => {
  const key = Object.keys(val)[0]
  const head = props.head.filter((v) => v.value === key)[0]
  let value = null
  if (val[key].length > 0) {
    if (head.filterMultiple) {
      value = val[key]
    } else {
      value = val[key][0]
    }
  }
  emit('handleFilter', { key, value })
}
const resetFilter = (key: any = null) => {
  key ? ref_table.value.clearFilter([key]) : ref_table.value.clearFilter()
}
const reset = (key: any = null) => {
  resetFilter(key)
  ref_table.value.clearSort()
}
watch(
  () => props.selected,
  (n: any) => {
    if (n.length === 0) {
      ref_table.value.clearSelection()
    } else {
      state.waitSelected = true
      props.data.forEach((v) => {
        ref_table.value.toggleRowSelection(
          v,
          n.some((s) => s[props.idKey] == v[props.idKey]),
        )
      })
      state.waitSelected = false
    }
  },
)
watch(
  () => [props.data, props.full, state.tableResizeFlag],
  () => {
    state.showBlock = false
    resizeTable()
  },
  { deep: true },
)
const resizeTable = () => {
  nextTick(() => {
    try {
      const bodyHeight =
        ref_czrTable.value?.querySelector('.el-table__body')?.clientHeight ||
        ref_czrTable.value?.querySelector('.el-table__empty-block')
          ?.clientHeight
      const headHeight = ref_czrTable.value.querySelector(
        '.el-table__header-wrapper',
      ).clientHeight
      const tableHeight = ref_tableMain.value.clientHeight
      const footMT = 25
      const blockHeight =
        bodyHeight + headHeight > tableHeight
          ? tableHeight
          : bodyHeight + headHeight
      state.tableContentHeight = blockHeight + footMT
      state.showBlock = true
    } catch (e) {
      console.log(e)
    }
  })
}
const initDrag = () => {
  nextTick(() => {
    if (props.dragable !== false) {
      const tbody = ref_table.value.$el.querySelector(
        '.el-table__body-wrapper tbody',
      )
      new Sortable(tbody, {
        animation: 150,
        handle: '.drag-icon', // 设置可拖拽行的类名(el-table自带的类名)
        onEnd: ({ newIndex, oldIndex }: any) => {
          console.log(newIndex)
          const d = [...props.data]
          const targetRow = d[oldIndex]
          d.splice(oldIndex, 1)
          d.splice(newIndex, 0, targetRow)
          emit('update:data', [...d])
          state.dragRefresh = false
          setTimeout(() => {
            state.dragRefresh = true
            initDrag()
          }, 0)
        },
      })
    }
  })
}
onMounted(() => {
  initDrag()
  formatTableHead(props.head)
  // CusContent组件下表格尺寸变化、或导致表格位置变化监听，所有会导致表格尺寸发生变化的dom添加name="czr-table-resize-dom"
  const resizeObserver = new ResizeObserver(() => {
    state.tableResizeFlag = !state.tableResizeFlag
  })
  resizeObserver.observe(ref_czrTable.value)
  const czrTableResizeDomArr = document.getElementsByName(
    'czr-table-resize-dom',
  )
  czrTableResizeDomArr.forEach((v) => {
    resizeObserver.observe(v)
  })
  onBeforeUnmount(() => {
    resizeObserver.disconnect()
  })
})
</script>

<style scoped lang="scss">
.czr-table {
  width: 100%;
  height: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  $czr-page-height: 32px;
  $czr-page-mt: 25px;
  position: relative;
  :deep(.el-popper) {
    max-width: 60% !important;
  }
  .czr-table-main {
    width: 100%;
    position: absolute;
    &.czr-table-main-no-foot {
      height: 100% !important;
    }
    :deep(.ct-table) {
      height: 100%;
    }
  }
  :deep(.ct-foot) {
    height: $czr-page-height;
    font-size: 14px;
    font-family: Microsoft YaHei;
    font-weight: 400;
    color: #999999;
    display: flex;
    justify-content: space-between;
    .total {
      display: flex;
      align-items: center;
    }
  }
  &:not(.czr-table-full) {
    .czr-table-main {
      height: calc(100% - #{$czr-page-height} - #{$czr-page-mt});
    }
  }
  &.czr-table-normal {
    .czr-table-main {
      :deep(.ct-table) {
        width: 100%;
        //height: calc(100% - #{$czr-page-height} - 20px);
        .el-checkbox__inner {
          &:after {
          }
        }
        $borderColor: #ffffff;
        $borderWidth: 2px;
        //  表格左边框
        &::before,
        .el-table__border-left-patch {
          display: none;
        }
        //  表格上边框
        .el-table__inner-wrapper::after {
          display: none;
        }
        //  表格右边框
        &.el-table--border::after {
          display: none;
        }
        //  表格下边框
        .el-table__inner-wrapper::before {
          display: none;
        }
        .el-table__header-wrapper,
        .el-table__fixed-right,
        .el-table__fixed {
          .el-table__header {
            tr {
              > th {
                border-left: $borderWidth solid $borderColor;
                border-top: $borderWidth solid $borderColor;
                border-right: none;
                border-bottom: none;
                background-color: #f5f5f5;
                height: 52px;
                .cell {
                  font-size: 14px;
                  font-family: 微软雅黑;
                  font-weight: 400;
                  color: #666666;
                  padding: 0 4px;
                  &.highlight {
                    color: #409eff;
                  }
                }
                &.required > .cell:before {
                  content: '*';
                  background-color: transparent;
                  color: var(--czr-error-color);
                  width: auto;
                  height: auto;
                }
              }
              &:first-child {
                > th {
                  border-top: none;
                  &:first-child {
                    border-left: none;
                  }
                }
              }
            }
          }
        }
        .el-table__body-wrapper,
        .el-table__fixed-body-wrapper {
          .el-scrollbar {
            height: unset;
            max-height: 100%;
            overflow-y: auto;
            .el-scrollbar__bar.is-horizontal {
              position: sticky;
            }
            .el-table__body {
              .el-table__row {
                -webkit-user-drag: element;
                > td {
                  border-right: none;
                  border-bottom-color: #f4f4f4;
                  .cell {
                    font-size: 14px;
                    font-family: 微软雅黑;
                    font-weight: 400;
                    color: #666666;
                    padding: 0 6px;
                    .el-link + .el-link {
                      margin-left: 10px;
                    }
                  }
                  &:not(.no-popover) {
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    word-break: break-all;
                  }
                }
              }
            }
          }
        }
      }
    }
    .ct-block {
      height: 600px;
    }
    :deep(.ct-foot) {
      z-index: 2;
      //margin-top: auto;
    }
  }
  &.czr-table-full {
    .czr-table-main {
      position: unset;
      //height: 100% !important;
    }
    :deep(.ct-foot) {
      margin-top: $czr-page-mt;
    }
  }
}

:deep(.single-column) {
  .cell {
    display: flex;
    justify-content: center;
    align-items: center;
    .single-circle {
      width: 16px;
      height: 16px;
      border: 1px solid rgba(96, 98, 102, 0.6);
      border-radius: 50%;
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center;
      &.active {
        background-color: #22a5fe;
        border-color: #22a5fe;
      }
      .single-circle-in {
        width: 6px;
        height: 6px;
        border-radius: 50%;
        background-color: #ffffff;
      }
    }
  }
}
</style>
